package com.self.auth.service.impl;

import com.self.auth.constant.LoginConstant;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @version v1.0
 * @ClassName: 自定义认证
 * @Description:
 * @Author: Mac
 * @Date: 2022/5/28 13:04
 */
@Service
public class UserSecurityServiceImpl implements UserDetailsService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * @Title: 登陆认证
     * @Description:
     * @Param [s]
     * @Return org.springframework.security.core.userdetails.UserDetails
     * @Author Mac
     * @Throws
     * @Date 2022/5/28 13:07
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String loginType = request.getParameter(LoginConstant.LOGIN_TYPE);
        if (StringUtils.isEmpty(loginType)){
            throw new AuthenticationServiceException(LoginConstant.LOGIN_TYPE+"登陆参数不能为空！");
        }
        String grantType = request.getParameter(LoginConstant.GRANT_TYPE);
        UserDetails userDetails = null;
        try {
            //如果是授权类型是refresh_token,则调整用户名
            if (LoginConstant.REFRESH_TOKEN.equalsIgnoreCase(grantType)){
                username = adjustUsername(username,loginType);
            }
            switch (loginType){
                case LoginConstant.ADMIN_TYPE:
                    userDetails = loadSysUserByUsername(username);
                    break;
                case LoginConstant.MEMBER_TYPE:
                    userDetails = loadMemberByUsername(username);
                    break;
                default:
                    throw new AuthenticationServiceException("暂不支持的登陆方式："+loginType);
            }
        } catch (IncorrectResultSizeDataAccessException e) {
            throw new UsernameNotFoundException("用户名:"+username+"不存在");
        }
        return userDetails;
    }

    private String adjustUsername(String username, String loginType) {
        if (LoginConstant.ADMIN_TYPE.equals(loginType)){
            return jdbcTemplate.queryForObject("SELECT `username` FROM sys_user where id = ?",
                    String.class,username);
        }
        if (LoginConstant.MEMBER_TYPE.equals(loginType)){
            return jdbcTemplate.queryForObject("SELECT `mobile` FROM user where id = ?",
                   String.class,username);
        }
        return username;
    }

    private UserDetails loadMemberByUsername(String username) {
        String sql = "SELECT `id`,`password`, `status` FROM `user` WHERE mobile = ? or email = ?";
        return jdbcTemplate.queryForObject(sql, new RowMapper<UserDetails>() {
            @Override
            public UserDetails mapRow(ResultSet resultSet, int i) throws SQLException {
                if (resultSet.wasNull()){
                    throw new UsernameNotFoundException("用户名:"+username+"不存在");
                }
                long id = resultSet.getLong("id");
                String password = resultSet.getString("password");
                int status = resultSet.getInt("status");

                return new User(String.valueOf(id),password,status==1,
                        true,
                        true,
                        true,
                        Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
            }
        },username,username);
    }

    private UserDetails loadSysUserByUsername(String username) {
         String sql = "SELECT `id` ,`username`, `password`, `status` FROM sys_user WHERE username = ? ";
         return jdbcTemplate.queryForObject(sql, new RowMapper<UserDetails>() {
             @Override
             public UserDetails mapRow(ResultSet resultSet, int i) throws SQLException {
                 if (resultSet.wasNull()){
                     throw new UsernameNotFoundException("用户名:"+username+"不存在");
                 }
                 long id = resultSet.getLong("id");
                 String password = resultSet.getString("password");
                 int status = resultSet.getInt("status");

                 return new User(String.valueOf(id),password,status==1,
                         true,
                         true,
                         true,
                         getSysUsrPermissions(id));
             }
         },username);
    }

    private Collection<? extends GrantedAuthority> getSysUsrPermissions(long id) {
        //当前角色
        String sql = "SELECT `code` FROM sys_role LEFT JOIN sys_user_role " +
                "ON sys_role.id = sys_user_role.role_id WHERE sys_user_role.user_id= ?";
        List<String> list = jdbcTemplate.queryForList(sql, String.class, id);
        if (CollectionUtils.isEmpty(list)){
           return Collections.emptySet();
        }
        List<String> permissions = null;
        if (list.contains(LoginConstant.ROLE_ADMIN)){
            permissions = jdbcTemplate.queryForList("SELECT `name` FROM sys_privilege", String.class);
        }else{
            permissions = jdbcTemplate.queryForList("SELECT sys_privilege.`name` FROM sys_privilege " +
                    "INNER JOIN sys_role_privilege " +
                    "ON sys_role_privilege.privilege_id = sys_privilege.id " +
                    "INNER JOIN sys_user_role  ON sys_role_privilege.role_id = sys_user_role.role_id " +
                    "WHERE sys_user_role.user_id = ?", String.class,id);
        }
        if (CollectionUtils.isEmpty(permissions)){
            return Collections.emptySet();
        }
       return permissions.stream().distinct().map(perm -> new SimpleGrantedAuthority(perm))
                .collect(Collectors.toSet());
    }
}
